package com.example.demo.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.demo.dao.BookShelfMapper;
import com.example.demo.dao.ScoreMapper;
import com.example.demo.model.BookShelf;
import com.example.demo.model.Score;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;


/**
 * 功能描述：定义一个工具类来封装计算相似度的方法
 *
 * @Author: Zhanghf
 * @Date: 2021/5/20 8:53
 */
@Component
public class RecUtils {
    @Autowired(required = false)
    private BookShelfMapper bookShelfMapper;
    @Autowired(required = false)
    private ScoreMapper scoreMapper;
    enum Status {
        Puton(1),
        Off(0);
        //已上架    //未上架
        private final Integer shelfStatus;

        private Status(Integer shelfStatus) {
            this.shelfStatus = shelfStatus;
        }

        public Integer getShelfStatus() {
            return shelfStatus;
        }
    }




    public double jkd(Integer userid1, Integer userid2)
     {
     /**
      * @Author Zhanghf
      * @Date 2021-11-01 19:03
      * @Description: 计算杰卡德相似度
      * @param userid1
      * @param userid2
      * @Return: double
     */
        List<BookShelf> bookShelfList1 = bookShelfMapper.selectList(new QueryWrapper<BookShelf>().eq("userid", userid1).select("bookid"));
        List<BookShelf> bookShelfList2 = bookShelfMapper.selectList(new QueryWrapper<BookShelf>().eq("userid", userid2));
        LinkedHashSet<Integer> selectbookid1=new  LinkedHashSet<Integer>();
        LinkedHashSet<Integer> selectbookid2=new  LinkedHashSet<Integer>();
        for (BookShelf bookShelf : bookShelfList1) {
            selectbookid1.add(bookShelf.getBookid());
        }
        for (BookShelf bookShelf : bookShelfList2) {
            selectbookid2.add(bookShelf.getBookid());
        }

        LinkedHashSet<Integer> unionlist = new LinkedHashSet<>();
        //Set集合自动去重(取并集
        unionlist.addAll(selectbookid1);
        unionlist.addAll(selectbookid2);
        //定义一个枚举类型 ?  枚举
        ArrayList<Integer> list1 = new ArrayList<>();
        ArrayList<Integer> list2 = new ArrayList<>();

        for (Integer integer : unionlist) {
            if (selectbookid1.contains(integer)) {
                list1.add(Status.Puton.shelfStatus);
            } else {
                list1.add(Status.Off.shelfStatus);
            }
        }
        for (Integer integer : unionlist) {
            if (selectbookid2.contains(integer)) {
                list2.add(Status.Puton.shelfStatus);
            } else {
                list2.add(Status.Off.shelfStatus);
            }
        }

        float mergeNum = 0;//并集元素个数
        float commonNum = 0;//相同元素个数（交集）
        int i = 0;
        while (i < list1.size()) {
            if (list1.get(i).equals(1)) {
                if ((list1.get(i).equals(list2.get(i)))) {
                    commonNum++;
                }
                mergeNum++;
            }
            if (list2.get(i).equals(1)) {
                mergeNum++;
            }
            i++;
        }
        mergeNum -= commonNum;
        double jaccard = commonNum / mergeNum;   //杰卡德相似度
        return jaccard;
    }

    public double pearson(Integer userid1, Integer userid2) {
        /**
         * @Author Zhanghf
         * @Date 2021-11-01 19:05
         * @Description: 计算皮尔逊相关系数
         * @param userid1
         * @param userid2
         * @Return: double
        */

        List<Score> bookidandcore1 = scoreMapper.selectList(new QueryWrapper<Score>() {
        }.select("bookid", "core").eq("userid", userid1));
        List<Score> bookidandcore2 = scoreMapper.selectList(new QueryWrapper<Score>() {
        }.select("bookid", "core").eq("userid", userid2));

        Map<Integer, Double> map1 = new HashMap<Integer, Double>();
        for (Score core : bookidandcore1) {
            map1.put(core.getBookid(), core.getCore());
        }
            Map<Integer, Double> map2 = new HashMap<Integer, Double>();
        for (Score core : bookidandcore2) {
            map2.put(core.getBookid(), core.getCore());
        }

        Map<Integer, Map<Integer, Double>> dataset = new HashMap<Integer, Map<Integer, Double>>();
        dataset.put(userid1, map1);
        dataset.put(userid2, map2);

        // 找出双方都评论过的电影,（皮尔逊算法要求）
        List<Integer> list = new ArrayList<Integer>();
        for (Map.Entry<Integer, Double> p1 : dataset.get(userid1).entrySet()) {
            if (dataset.get(userid2).containsKey(p1.getKey())) {
                list.add(p1.getKey());
            }
        }

        double sumX = 0.0;
        double sumY = 0.0;
        double sumX_Sq = 0.0;
        double sumY_Sq = 0.0;
        double sumXY = 0.0;
        int N = list.size();
        for (Integer name : list) {
            Map<Integer, Double> p1Map = map1;
            Map<Integer, Double> p2Map = map2;
            sumX += p1Map.get(name);
            sumY += p2Map.get(name);
            sumX_Sq += Math.pow(p1Map.get(name), 2);
            sumY_Sq += Math.pow(p2Map.get(name), 2);
            sumXY += p1Map.get(name) * p2Map.get(name);
        }
        double numerator = sumXY - sumX * sumY / N;
        double denominator = Math.sqrt((sumX_Sq - sumX * sumX / N)
                * (sumY_Sq - sumY * sumY / N));
        // 分母不能为0
        if (denominator == 0) {
            return 0;
        }
        return numerator / denominator;
    }

}
